package main

// 实现set方法
// 参考https://allenwu.itscoder.com/set-in-go
import (
	"fmt"
	"sync"
	"time"
)

// 定义map的值为Exists
var Exists = struct{}{}

type Set struct {
	sync.RWMutex
	m map[interface{}]struct{}
}

// 新建Set
func NewSet() *Set {
	s := &Set{}
	s.m = make(map[interface{}]struct{})
	return s
}

// 为Set添加元素
func (s *Set) Add(items ...interface{}) {
	for _, item := range items {
		s.Lock()
		s.m[item] = Exists
		s.Unlock()
	}
}

// 合并两个Set的元素
func (s *Set) Merge(source *Set) {
	tmp := source.PrintElement()
	for _, v := range tmp {
		s.Add(v)
	}
}

// 查询Set中的所有元素
func (s *Set) PrintElement() []interface{} {
	var tmp []interface{}
	for i, _ := range s.m {
		tmp = append(tmp, i)
	}
	return tmp
}

// 查询元素是否再Set中
func (s *Set) JudgeElement(item interface{}) bool {
	_, exists := s.m[item]
	return exists
}
func (s *Set) Size() int {
	size := len(s.m)
	return size
}

// 删除Set中的一个元素
func (s *Set) Del(item interface{}) {
	delete(s.m, item)
}

func (s *Set) Clear() {
	s.m = make(map[interface{}]struct{})
}
func main() {

	s := NewSet()
	// 10个协程并发写
	for i := 0; i < 10; i++ {
		go func(i int) {
			s.Add(i)
		}(i)
	}
	time.Sleep(time.Second * 3)
	// 查询s中的所有元素
	fmt.Println(s.PrintElement()) //[0 3 9 6 2 1 4 5 7 8]
	// 删除s中的8
	s.Del(8)
	// 查询一个元素
	item := 9
	if s.JudgeElement(item) {
		fmt.Println(item, " exists")
	} else {
		fmt.Println(item, " not found!")
	}

	// 将x合并到s中
	x := NewSet()
	x.Add("X", 2, 3, "wu")
	s.Merge(x)
	fmt.Println(s.PrintElement())
}

// NewSet方法应该要用到Add方法，想到避免定义出得结构是一样和实现线程安全的很不错了
